package javapop.framework.parser.tuple;

import java.util.List;

import javapop.framework.ParseContext;
import javapop.framework.ParseError;
import javapop.framework.ParseInput;
import javapop.framework.ParseResult;
import javapop.framework.Parser;
import javapop.framework.parser.TupleParser;
import javapop.utils.Triple;

public class Three<T1, T2, T3> extends Parser<Triple<T1,T2,T3>> {
	private TupleParser parser;
	
	public Three() {
		parser = new TupleParser();
	}
		
	public Three<T1,T2,T3> then(Parser<?> silent) {
		parser.addSilent(silent);
		return this;
	}
	
	public Three<T1,T2,T3> first(Parser<T1> first) {
		if(parser.getArity()>=1) {
			throw new IllegalStateException("First component already set");
		}
		parser.addComponent(first);
		return this;
	}
	
	public Three<T1,T2,T3> second(Parser<T2> first) {
		if(parser.getArity()==0) {
			throw new IllegalStateException("First component missing");
		}
		if(parser.getArity()>1) {
			throw new IllegalStateException("Second component already set");
		}
		parser.addComponent(first);
		return this;
	}

	public Three<T1,T2,T3> third(Parser<T3> first) {
		if(parser.getArity()==0) {
			throw new IllegalStateException("First component missing");
		}
		if(parser.getArity()==1) {
			throw new IllegalStateException("Second component missing");
		}
		if(parser.getArity()>2) {
			throw new IllegalStateException("Third component already set");
		}
		parser.addComponent(first);
		return this;
	}
	
	public Three<T1,T2,T3> fatalFrom(int ref) {
		parser.setFatalFrom(ref);
		return this;
	}
	

	@Override
	public ParseResult<Triple<T1,T2,T3>> eval(ParseContext ctx, ParseInput input) {
		ParseResult<List<?>> result = parser.parse(ctx, input);
		if(result.isError()) {
			return (ParseResult) result.asError();
		}
		List<?> results = result.getResult();
		if(results.size()!=3) {
			return (ParseResult) new ParseError("Wrong cardinality: expected 3 got "+results.size());
		}
		T1 first = (T1) results.get(0);
		T2 second = (T2) results.get(1);
		T3 third = (T3) results.get(2);
		Triple<T1,T2,T3> triple = new Triple<T1, T2, T3>(first,second,third);
		return buildResult(triple);
	}

	@Override
	public String getDescription() {
		return parser.getDescription();
	}
	
	@Override
	public boolean isMemoized() {
		return false;
	}
	

}
